/**
 * 重定向 302/307
 * 前端一般两种请求，一种是浏览器地址访问，这种可以自动重定向
 * 而ajax请求是是局部刷新，自动跳转后将获取登录页作为响应体，而不会自动跳转。可以通过前端代码约定识别指定响应头，手动跳转
 * 大多数JavaScript库（如jQuery、Axios等）在发送AJAX请求时，会自动在请求头中添加 X-Requested-With: XMLHttpRequest。
 * 如果是原生js写的请求，则需要前端手动加上这个请求头，以便后端识别。
 * 针对ajax请求重定向的前后端约定：status=200，响应头REDIRECT存在表示要重定向，CONTEXTPATH响应头指向重定向地址
 */
function ajax(uri, method, data, callback) {
    let xhr = new XMLHttpRequest()
    xhr.open(method, uri, true)
    xhr.setRequestHeader("x-requested-with", "XMLHttpRequest")
    xhr.onload = function () {
        if (xhr.status === 200) {
            // 判断是否重定向(和后端约定)
            if ("REDIRECT" === xhr.getResponseHeader("REDIRECT")) {
                let redirectUrl = xhr.getResponseHeader("CONTEXTPATH");
                if (redirectUrl !== null) {
                    console.log("手动重定向发生: redirectUrl -> " + redirectUrl)
                    window.location.href = redirectUrl
                } else {
                    alert("后端传递了REDIRECT却没有传递CONTEXTPATH，什么情况？无法手动重定向")
                }
                return
            }
            let result = JSON.parse(xhr.responseText)
            callback(result)
        } else {
            alert(xhr.status + ": " + xhr.responseText)
        }
    }
    doSendReqData(xhr, data)
}

/**
 * 根据不同数据类型调整不同content-type
 * @param xhr 请求
 * @param data 请求体入参，可以是 URLSearchParams、FormData、object
 */
function doSendReqData(xhr, data) {
    if (data === null) {
        xhr.send(data)
        return
    }

    // 表单数据的标准格式
    // var params = new URLSearchParams();
    // params.append("key1", "value1");
    // params.append("key2", "value2");
    // var data = params.toString(); // 输出: "key1=value1&key2=value2"
    if (data instanceof URLSearchParams) {
        // 注意GET请求需将参数附带在uri中，这里设置无效，因为GET请求不会发送请求体数据
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
        xhr.send(data.toString())
        return
    }

    // 表单上传文件格式
    // let form = new FormData()
    // form.append("k1", "v1")
    if (data instanceof FormData) {
        xhr.send(data)// 直接发送即可
        return
    }

    // 判断普通对象（Plain Object）
    // data={"k1":"v1","k2":2}
    if (typeof data === "object" &&
        Object.prototype.toString.call(data) === "[object Object]") {
        xhr.setRequestHeader("Content-Type", "application/json")
        xhr.send(JSON.stringify(data))
        return
    }

    alert("不支持的data参数类型: " + data.type)
}